/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       creature_traits.cpp

	$Header: /game/creature_traits.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "creature_traits.h"

#include <algorithm>
#include "bitmap_pool.h"
#include "bitmap_group_cache.h"
#include "creature_ability.h"
#include "creature_type.h"
#include "elements_of.h"
#include "external_string.h"
#include "missile_type.h"
#include "spell_properties.h"
#include "spell_set.h"
#include "string_insensitive_compare.h"
#include "table.h"
#include "table_ptr.h"
#include "town_building.h"
#include "town_properties.h"
#include "town_type.h"

namespace
{
	t_creature_traits k_creature_traits[k_creature_type_count];
	t_table_cache     g_creature_table( "creatures" );

	struct t_creature_dwelling
	{
		t_town_building dwelling;
		t_creature_type creature;
	};

	t_creature_dwelling const k_dwellings[] =
	{
		// life creature generators
		{ k_town_dwelling_squire,		k_squire },
		{ k_town_dwelling_crossbowman,	k_crossbowman },
		{ k_town_dwelling_pikeman,		k_pikeman },
		{ k_town_dwelling_ballista,		k_ballista },
		{ k_town_dwelling_crusader,		k_crusader },
		{ k_town_dwelling_monk,			k_monk },
		{ k_town_dwelling_champion,		k_champion },
		{ k_town_dwelling_angel,		k_angel },

		// order creature generators
		{ k_town_dwelling_dwarf,		k_dwarf },
		{ k_town_dwelling_halfling,		k_halfling },
		{ k_town_dwelling_golem,		k_gold_golem },
		{ k_town_dwelling_mage,			k_mage },
		{ k_town_dwelling_naga,			k_naga },
		{ k_town_dwelling_genie,		k_genie },
		{ k_town_dwelling_dragon_golem, k_dragon_golem },
		{ k_town_dwelling_titan,		k_titan },

		// death creature generators
		{ k_town_dwelling_skeleton,		k_skeleton },
		{ k_town_dwelling_imp,			k_imp },
		{ k_town_dwelling_ghost,		k_ghost },
		{ k_town_dwelling_cerberus,		k_cerberus },
		{ k_town_dwelling_vampire,		k_vampire },
		{ k_town_dwelling_venom_spawn,	k_venom_spawn },
		{ k_town_dwelling_bone_dragon,	k_bone_dragon },
		{ k_town_dwelling_devil,		k_devil },

		// chaos creature generators
		{ k_town_dwelling_bandit,		k_bandit },
		{ k_town_dwelling_orc,			k_orc },
		{ k_town_dwelling_medusa,		k_medusa },
		{ k_town_dwelling_minotaur,		k_minotaur },
		{ k_town_dwelling_nightmare,	k_nightmare },
		{ k_town_dwelling_efreet,		k_efreet },
		{ k_town_dwelling_hydra,		k_hydra },
		{ k_town_dwelling_black_dragon, k_black_dragon },

		// nature creature generators
		{ k_town_dwelling_wolf,			k_wolf },
		{ k_town_dwelling_fairie,		k_sprite },
		{ k_town_dwelling_tiger,		k_white_tiger },
		{ k_town_dwelling_elf,			k_elf },
		{ k_town_dwelling_griffin,		k_griffin },
		{ k_town_dwelling_unicorn,		k_unicorn },
		{ k_town_dwelling_pheonix,		k_phoenix },
		{ k_town_dwelling_fairie_dragon, k_faerie_dragon },

		// might creature generators
		{ k_town_dwelling_berserker,	k_berserker },
		{ k_town_dwelling_centaur,		k_centaur },
		{ k_town_dwelling_nomad,		k_nomad },
		{ k_town_dwelling_harpy,		k_harpy },
		{ k_town_dwelling_ogre,			k_ogre_mage },
		{ k_town_dwelling_cyclops,		k_cyclops },
		{ k_town_dwelling_thunderbird,	k_thunderbird },
		{ k_town_dwelling_behemoth,		k_behemoth }
	};

	// -----------------------------------------------------------
	// ability icons of creatures
	// -----------------------------------------------------------
	class t_abilities : public std::vector<t_creature_ability>
	{
	public:
		t_abilities( t_creature_type creature, t_creature_ability ability_1 );
		t_abilities( t_creature_type creature, t_creature_ability ability_1,
			         t_creature_ability ability_2 );
		t_abilities( t_creature_type creature, t_creature_ability ability_1,
			         t_creature_ability ability_2,  t_creature_ability ability_3 );
		t_abilities( t_creature_type creature,		t_creature_ability ability_1,
			         t_creature_ability ability_2,  t_creature_ability ability_3,
					 t_creature_ability ability_4 );
		t_creature_type get_type() const;
	protected:
		t_creature_type m_type;
	};

	inline t_creature_type t_abilities::get_type() const
	{
		return m_type;
	}

	// -----------------------------------------------------------
	// ability icons of creatures
	// -----------------------------------------------------------
	static t_abilities const k_abilities[] =
	{
		t_abilities( k_air_elemental,	k_ability_flying, k_ability_elemental, 
										k_ability_insubstantial ),
		t_abilities( k_angel,			k_ability_flying, k_ability_resurrection ),
		t_abilities( k_ballista,		k_ability_ranged, k_ability_mechanical, 
										k_ability_long_range, k_ability_siege_machine ),
		t_abilities( k_bandit,			k_ability_stealth ),
		t_abilities( k_beholder,		k_ability_ranged, k_ability_flying, k_ability_random_curse ),
		t_abilities( k_behemoth,		k_ability_strength ),
		t_abilities( k_black_dragon,	k_ability_flying, k_ability_magic_immunity,
										k_ability_breath_attack ),
		t_abilities( k_bone_dragon,		k_ability_flying, k_ability_undead, k_ability_skeletal, 
										k_ability_panic ),
		t_abilities( k_centaur,			k_ability_ranged, k_ability_normal_melee,
										k_ability_short_range ),
		t_abilities( k_cerberus,		k_ability_no_retaliation, k_ability_3_headed_attack ),
		t_abilities( k_champion,		k_ability_first_strike, k_ability_charging ),
		t_abilities( k_crossbowman,		k_ability_ranged, k_ability_long_range ),
		t_abilities( k_crusader,		k_ability_strikes_twice, k_ability_death_protection ),
		t_abilities( k_cyclops,			k_ability_ranged, k_ability_area_effect ),
		t_abilities( k_venom_spawn,		k_ability_ranged, k_ability_poison ),
		t_abilities( k_devil,			k_ability_teleport, k_ability_summons_demons,
										k_ability_life_protection ),
		t_abilities( k_dragon_golem,	k_ability_first_strike, k_ability_first_strike_immunity,
		                                k_ability_mechanical ),
		t_abilities( k_dwarf,			k_ability_magic_resistance ),
		t_abilities( k_earth_elemental,	k_ability_elemental, k_ability_magic_resistance ),
		t_abilities( k_efreet,			k_ability_flying, k_ability_fire_shield,
		                                k_ability_fire_attack, k_ability_fire_resistance ),
		t_abilities( k_elf,				k_ability_ranged, k_ability_shoots_twice, 
										k_ability_ranged_first_strike ),
		t_abilities( k_faerie_dragon,		k_ability_flying, k_ability_spellcaster, 
		                                k_ability_magic_mirror ),
		t_abilities( k_fire_elemental,	k_ability_ranged, k_ability_elemental, 
										k_ability_fire_attack, k_ability_fire_resistance ),
		t_abilities( k_gargoyle,		k_ability_flying, k_ability_elemental,
		                                k_ability_stone_skin ),
		t_abilities( k_genie,			k_ability_flying, k_ability_spellcaster ),
		t_abilities( k_ghost,			k_ability_flying, k_ability_undead, k_ability_aging,
										k_ability_insubstantial ),
		t_abilities( k_berserker,		k_ability_strikes_twice, k_ability_berserk ),
		t_abilities( k_gold_golem,		k_ability_mechanical, k_ability_magic_resistance ),
		t_abilities( k_griffin,			k_ability_flying, k_ability_unlimited_retaliation ),
		t_abilities( k_halfling,		k_ability_ranged, k_ability_giantslayer ),
		t_abilities( k_harpy,			k_ability_flying, k_ability_no_retaliation,
										k_ability_strike_and_return ),
		t_abilities( k_hydra,			k_ability_no_retaliation, k_ability_hydra_strike ),
		t_abilities( k_ice_demon,		k_ability_freeze, k_ability_cold_attack, 
										k_ability_cold_resistance ),
		t_abilities( k_imp,				k_ability_flying, k_ability_mana_leech ),
		t_abilities( k_leprechaun,		k_ability_fortune ),
		t_abilities( k_mage,			k_ability_spellcaster ),
		t_abilities( k_mantis,			k_ability_flying, k_ability_first_strike, 
										k_ability_binding ),
		t_abilities( k_medusa,			k_ability_ranged, k_ability_normal_melee, 
										k_ability_unlimited_shots, k_ability_stone_gaze ),
		t_abilities( k_mermaid,			k_ability_hypnotize ),
		t_abilities( k_minotaur,		k_ability_block ),
		t_abilities( k_monk,			k_ability_ranged, k_ability_death_protection ),
		t_abilities( k_mummy,			k_ability_undead, k_ability_curse ),
		t_abilities( k_naga,			k_ability_no_retaliation ),
		t_abilities( k_nightmare,		k_ability_terror ),
		t_abilities( k_nomad,			k_ability_first_strike ),
		t_abilities( k_ogre_mage,		k_ability_bloodlust ),
		t_abilities( k_orc,				k_ability_ranged, k_ability_normal_melee,
										k_ability_short_range ),
		t_abilities( k_peasant,			k_ability_taxpayer ),
		t_abilities( k_phoenix,			k_ability_flying, k_ability_rebirth, 
										k_ability_breath_attack, k_ability_fire_resistance ),
		t_abilities( k_pikeman,			k_ability_long_weapon, k_ability_first_strike_immunity ),
		t_abilities( k_pirate,			k_ability_sea_bonus ),
		t_abilities( k_satyr,			k_ability_mirth ),
		t_abilities( k_sea_monster,		k_ability_devouring ),
		t_abilities( k_skeleton,		k_ability_undead, k_ability_skeletal ),
		t_abilities( k_squire,			k_ability_stunning ),
		t_abilities( k_sprite,			k_ability_flying, k_ability_no_retaliation ),
		t_abilities( k_thunderbird,		k_ability_flying, k_ability_lightning ),
		t_abilities( k_titan,			k_ability_ranged, k_ability_normal_melee,
										k_ability_chaos_protection ),
		t_abilities( k_troglodyte,		k_ability_blind ),
		t_abilities( k_troll,			k_ability_regeneration ),
		t_abilities( k_unicorn,			k_ability_blinding ),
		t_abilities( k_vampire,			k_ability_undead, k_ability_flying, 
		                                k_ability_no_retaliation, k_ability_vampire ),
		t_abilities( k_waspwort,		k_ability_ranged, k_ability_weakness ),
		t_abilities( k_water_elemental,	k_ability_elemental, k_ability_spellcaster,
										k_ability_cold_resistance, k_ability_cold_attack ),
		t_abilities( k_white_tiger,		k_ability_first_strike ),
		t_abilities( k_wolf,			k_ability_strikes_twice ),
		t_abilities( k_zombie,          k_ability_undead, k_ability_toughness ),
	};

	enum {
		k_keyword_column,
		k_name_column,
		k_name_with_article_column,
		k_plural_column,
		k_plural_with_article_column,
		k_level_column,
		k_alignment_column,
		k_hit_points_column,
		k_damage_low_column,
		k_damage_high_column,
		k_attack_skill_column,
		k_defense_skill_column,
		k_move_column,
		k_speed_column,
		k_shots_column,
		k_spell_points_column,
		k_spell_power_column,
		k_weekly_growth_column,
		k_gold_column,
		k_wood_column,
		k_ore_column,
		k_crystal_column,
		k_sulfur_column,
		k_mercury_column,
		k_gems_column,
		k_experience_column,
		k_short_help_column,
		k_long_help_column
	};
};

t_bitmap_group_cache const k_creature_portraits_52( "icons.creatures.52" );
t_bitmap_group_cache const k_creature_portraits_82( "icons.creatures.82" );

// -----------------------------------------------------------
// ability icons of creatures
// -----------------------------------------------------------
t_abilities::t_abilities( t_creature_type creature, t_creature_ability ability_1 )
{
	m_type = creature;
	push_back( ability_1 );
}

// -----------------------------------------------------------
// ability icons of creatures
// -----------------------------------------------------------
t_abilities::t_abilities( t_creature_type creature, t_creature_ability ability_1,
					      t_creature_ability ability_2 )
{
	m_type = creature;
	push_back( ability_1 );
	push_back( ability_2 );
}

// -----------------------------------------------------------
// ability icons of creatures
// -----------------------------------------------------------
t_abilities::t_abilities( t_creature_type creature,		t_creature_ability ability_1,
						  t_creature_ability ability_2, t_creature_ability ability_3 )
{
	m_type = creature;
	push_back( ability_1 );
	push_back( ability_2 );
	push_back( ability_3 );
}

// -----------------------------------------------------------
// ability icons of creatures
// -----------------------------------------------------------
t_abilities::t_abilities( t_creature_type creature,		t_creature_ability ability_1,
						  t_creature_ability ability_2, t_creature_ability ability_3,
						  t_creature_ability ability_4 )
{
	m_type = creature;
	push_back( ability_1 );
	push_back( ability_2 );
	push_back( ability_3 );
	push_back( ability_4 );
}

// ------------------------------------------------------------
// set abilities
// ------------------------------------------------------------
static void set_abilities()
{
	int				i;
	int             j;
	t_creature_type creature;

	for (i = 0; i < ELEMENTS_OF( k_abilities); i++)
	{
		creature = k_abilities[i].get_type();
		assert( creature < k_creature_type_count );

		t_creature_traits& traits = k_creature_traits[creature];

		traits.abilities = k_abilities[i];
		for (j = 0; j < (int)traits.abilities.size(); j++)
			traits.ability_set.set( traits.abilities[j] );
	}
}

// ------------------------------------------------------------
// set the creature dwellings
// ------------------------------------------------------------
static void set_creature_dwellings()
{
	int i;
	t_creature_type creature;

	for (i = 0; i < ELEMENTS_OF( k_dwellings ); i++)
	{
		creature = k_dwellings[i].creature;
		assert( creature < k_creature_type_count );
		k_creature_traits[creature].dwelling = k_dwellings[i].dwelling;
	}
}

// ------------------------------------------------------------
// set the creature portraits
// ------------------------------------------------------------
static std::vector<t_string_pair> const& get_definitions()
{
	static std::vector<t_string_pair> definitions;

	t_string_pair              definition;

	static bool initialized = false; 

	if (initialized)
		return definitions;

	initialized = true;

	int i;

	definition.value = 0;
	definitions.reserve( k_creature_type_count );
	for (i = 0; i < k_creature_type_count; i++)
	{
		definition.keyword = get_keyword( t_creature_type(i) );
		definitions.push_back( definition );
	}
	return definitions;
}

static t_bitmap_pool& get_portraits_52()
{
	static t_bitmap_pool k_portraits( &k_creature_portraits_52, &(*get_definitions().begin()),
		                              get_definitions().size() );

	return k_portraits;
}

static t_bitmap_pool& get_portraits_82()
{
	static t_bitmap_pool k_portraits( &k_creature_portraits_82, &(*get_definitions().begin()),
		                              get_definitions().size() );

	return k_portraits;
}

static void set_portraits()
{
	int i;

	for (i = 0; i < k_creature_type_count; i++)
		k_creature_traits[i].portrait_id = get_portraits_52().find( get_keyword( t_creature_type(i) ) );
}

// ------------------------------------------------------------
// read spreadsheet with attributes of town buildings
// ------------------------------------------------------------
static void read_traits()
{
	static bool initialized = false;

	if (initialized)
		return;
	initialized = true;

	// initialize keyword for buildings
	t_table_ptr                    table = g_creature_table.get();
	t_table::iterator              line;
	t_creature_traits              traits;
	t_creature_type                creature;
	std::string                    keyword;

	// for each line in the spreadsheet
	line = table->begin();
	line++;
	line++; // skip 2 header lines
	for (; line != table->end(); line++)
	{
		if (line->size() == 0)
			continue;

		keyword = (*line)[k_keyword_column];

		if (keyword.empty())
			continue;

		creature = get_creature( keyword );
		if (creature == k_creature_none)
			continue;
		assert( creature < k_creature_type_count );

		traits.name = (*line)[k_name_column];
		traits.name_with_article = (*line)[k_name_with_article_column];
		traits.plural_name = (*line)[k_plural_column];
		traits.plural_name_with_article = (*line)[k_plural_with_article_column];
		traits.level		= atoi( (*line)[k_level_column].c_str() );
		
		traits.alignment	= get_town_type( (*line)[k_alignment_column].c_str() );
		traits.hit_points		= atoi( (*line)[k_hit_points_column].c_str() );
		traits.damage_low		= atoi( (*line)[k_damage_low_column].c_str() );
		traits.damage_high		= atoi( (*line)[k_damage_high_column].c_str() );
		traits.attack_skill		= (float)(atoi( (*line)[k_attack_skill_column].c_str() ) / 10.0);
		traits.defense_skill	= (float)(atoi( (*line)[k_defense_skill_column].c_str() ) / 10.0);
		traits.movement			= atoi( (*line)[k_move_column].c_str() );
		traits.speed			= atoi( (*line)[k_speed_column].c_str() );
		traits.shots			= atoi( (*line)[k_shots_column].c_str() );
		traits.spell_points		= atoi( (*line)[k_spell_points_column].c_str() );
		traits.spell_power		= atoi( (*line)[k_spell_power_column].c_str() );
		traits.weekly_growth	= atoi( (*line)[k_weekly_growth_column].c_str() );
		traits.cost[k_gold]		= atoi( (*line)[k_gold_column].c_str() );
		traits.cost[k_wood]		= atoi( (*line)[k_wood_column].c_str() );
		traits.cost[k_ore]		= atoi( (*line)[k_ore_column].c_str() );
		traits.cost[k_crystal]	= atoi( (*line)[k_crystal_column].c_str() );
		traits.cost[k_sulfur]	= atoi( (*line)[k_sulfur_column].c_str() );
		traits.cost[k_mercury]	= atoi( (*line)[k_mercury_column].c_str() );
		traits.cost[k_gems]		= atoi( (*line)[k_gems_column].c_str() );
		traits.experience		= atoi( (*line)[k_experience_column].c_str() );
		traits.short_help_text	= (*line)[k_short_help_column];
		traits.help_text		= (*line)[k_long_help_column];
		traits.dwelling			= k_town_no_building;

		k_creature_traits[creature] = traits;
	}
	set_creature_dwellings();
	set_portraits();
	set_abilities();
}

// ------------------------------------------------------------
// get creature traits
// ------------------------------------------------------------
t_creature_traits const& get_traits( t_creature_type creature )
{
	assert( creature < k_creature_type_count );
	read_traits();
	return k_creature_traits[creature];
}

// ------------------------------------------------------------
// get appropriate name
// ------------------------------------------------------------
std::string get_creature_name( t_creature_type type, int amount, bool include_article, bool upper_case )
{
	std::string			  name;
	std::string::iterator iter;

	t_creature_traits const& traits = get_traits( type );

	if (include_article)
	{
		if (amount == 1)
			name = traits.name_with_article;
		else
			name = traits.plural_name_with_article;
	}
	else
	{
		if (amount == 1)
			name = traits.name;
		else
			name = traits.plural_name;
	}

	if( upper_case )
	{
		std::transform( name.begin(), name.begin()+1, name.begin(), toupper );
		for( iter = name.begin(); iter != name.end(); ++iter )
		{

			if( (*iter) == ' ' )
			{
				if( (iter+1) != name.end() )
					std::transform( iter+1, iter+2, iter+1, toupper );
			}
		}
	}

	return name;
}

// ------------------------------------------------------------
// get portrait for creature
// ------------------------------------------------------------
t_bitmap_layer_ptr get_creature_portrait( t_creature_type creature, int width )
{
	assert( creature < k_creature_type_count );
	read_traits();
	if (width < 82)
		return get_portraits_52().get( k_creature_traits[creature].portrait_id );
	return get_portraits_82().get( k_creature_traits[creature].portrait_id );
}


// ------------------------------------------------------------
// get spells known by creature
// ------------------------------------------------------------
namespace
{
	struct t_creature_knowledge
	{
		t_creature_type creature;
		t_spell         spell;
	};

	class t_creature_spell_library
	{
	public:
		t_creature_spell_library();
		t_spell	get_default_spell( t_creature_type creature ) const;
		bool	knows( t_creature_type creature, t_spell spell ) const;
	protected:
		t_spell		m_default[k_creature_type_count];
		t_spell_set m_data[k_creature_type_count];
	};

	inline bool t_creature_spell_library::knows( t_creature_type creature, t_spell spell ) const
	{
		return m_data[creature][spell];
	}

	inline t_spell t_creature_spell_library::get_default_spell( t_creature_type creature ) const
	{
		return m_default[creature];
	}
};

// --------------------------------------------------------------
// initialize creature knowledge
// --------------------------------------------------------------
t_creature_spell_library::t_creature_spell_library()
{
	// note : first spell in list will become default for this creature, if possible.
	t_creature_knowledge const data[] =
	{
		{	k_angel,			k_spell_resurrection },
		{	k_devil,			k_spell_summon_demon },

		{	k_faerie_dragon,	k_spell_lightning },
		{	k_faerie_dragon,	k_spell_confusion },
		{	k_faerie_dragon,	k_spell_fire_ring },
		{	k_faerie_dragon,	k_spell_fireball },

		{	k_genie,			k_spell_ice_bolt },
		{	k_genie,			k_spell_order_slow },
		{	k_genie,			k_spell_cowardice },
		{	k_genie,			k_spell_illusionary_ally },
		{	k_genie,			k_spell_song_of_peace },
		{	k_genie,			k_spell_spiritual_fervor },

		{	k_leprechaun,		k_spell_fortune },

		{	k_mage,				k_spell_magic_fist },
		{	k_mage,				k_spell_curse },
		{	k_mage,				k_spell_poison },
		{	k_mage,				k_spell_raise_skeletons },
		{	k_mage,				k_spell_blur },

		{	k_nightmare,		k_spell_terror },

		{	k_ogre_mage,		k_spell_bloodlust },

		{	k_phoenix,			k_spell_rebirth },
	
		{	k_satyr,			k_spell_spiritual_fervor },

		{	k_water_elemental,	k_spell_ice_bolt },
		{	k_water_elemental,	k_spell_quicksand },
		{	k_water_elemental,	k_spell_slow },
		{	k_water_elemental,	k_spell_weakness },
	};

	int i;

	for (i = 0; i < k_creature_type_count; ++i)
	{
		m_default[i] = k_spell_none;
	}

	t_creature_type creature;
	t_spell			spell;

	for (i = 0; i < ELEMENTS_OF( data ); i++)
	{
		creature = data[i].creature;
		spell = data[i].spell;

		m_data[creature].set( spell );
		if (m_default[creature] == k_spell_none && is_single_target( spell ))
			m_default[creature] = spell;
	}
}

bool is_ownable( t_creature_type creature )
{
	return creature != k_mermaid && creature != k_sea_monster;
}

bool is_sea_creature( t_creature_type creature )
{
	return creature == k_mermaid || creature == k_sea_monster;
}

static t_creature_spell_library const& get_creature_spells()
{
	static t_creature_spell_library const library;

	return library;
}

bool knows_spell( t_creature_type creature, t_spell spell )
{
	return get_creature_spells().knows( creature, spell );
}

t_spell get_default_spell( t_creature_type creature )
{
	return get_creature_spells().get_default_spell( creature );
}
// --------------------------------------------------------------
// initialize creature missiles
// --------------------------------------------------------------
namespace
{
	struct t_missile_pair
	{
		t_creature_type creature;
		t_missile_type  missile;
	};
};

t_missile_type get_missile_type( t_creature_type creature )
{
	static bool           initialized = false;
	static t_missile_type missiles[k_creature_type_count];

	if (!initialized)
	{
		int            i;
		t_missile_pair missile_list[] =
		{
			{ k_ballista,		k_missile_heavy_bolt },
			{ k_beholder,		k_missile_beam },
			{ k_centaur,		k_missile_spear },
			{ k_crossbowman,	k_missile_arrow },
			{ k_cyclops,		k_missile_boulder },
			{ k_venom_spawn,	k_missile_spittle },
			{ k_elf,			k_missile_arrow },
			{ k_fire_elemental,	k_missile_fire_bolt },
			{ k_halfling,		k_missile_pebble },
			{ k_mage,			k_missile_magic },
			{ k_monk,			k_missile_magic },
			{ k_orc,			k_missile_axe },
			{ k_titan,			k_missile_lightning },
			{ k_waspwort,		k_missile_thorn },

		};

		initialized = true;
		for (i = 0; i < k_creature_type_count; i++)
			missiles[i] = k_missile_none;
		for (i = 0; i < ELEMENTS_OF( missile_list ); i++)
			missiles[missile_list[i].creature] = missile_list[i].missile;
	}
	return missiles[creature];
}

enum
{
	k_size_few,
	k_size_several,
	k_size_band,
	k_size_dozens,
	k_size_scores,
	k_size_company,
	k_size_hundreds,
	k_size_host,
	k_size_legion,
	k_size_thousands,

	k_army_size_count
};

static t_external_string const k_army_size_names[k_army_size_count][k_article_type_count] =
{
	{ 
		t_external_string( "few.creatures" ),
		t_external_string( "few.a.creatures" ),
		t_external_string( "few.the.creatures" )
	},
	{ 
		t_external_string( "several.creatures" ),
		t_external_string( "several.a.creatures" ),
		t_external_string( "several.the.creatures" )
	},
	{
		t_external_string( "band.creatures" ),
		t_external_string( "band.a.creatures" ),
		t_external_string( "band.the.creatures" ),
	},
	{
		t_external_string( "dozens.creatures" ),
		t_external_string( "dozens.a.creatures" ),
		t_external_string( "dozens.the.creatures" ),
	},
	{
		t_external_string( "scores.creatures" ),
		t_external_string( "scores.a.creatures" ),
		t_external_string( "scores.the.creatures" ),
	},
	{
		t_external_string( "company.creatures" ),
		t_external_string( "company.a.creatures" ),
		t_external_string( "company.the.creatures" )
	},
	{
		t_external_string( "hundreds.creatures" ),
		t_external_string( "hundreds.a.creatures" ),
		t_external_string( "hundreds.the.creatures" ),
	},
	{
		t_external_string( "host.creatures" ),
		t_external_string( "host.a.creatures" ),
		t_external_string( "host.the.creatures" )
	},
	{
		t_external_string( "legion.creatures" ),
		t_external_string( "legion.a.creatures" ),
		t_external_string( "legion.the.creatures" )
	},
	{
		t_external_string( "thousands.creatures" ),
		t_external_string( "thousands.a.creatures" ),
		t_external_string( "thousands.the.creatures" )
	}
};

std::string get_army_size_name( int amount, t_article_type article )
{
	if (amount < 5)
		return k_army_size_names[k_size_few][article];
	if (amount < 10)
		return k_army_size_names[k_size_several][article];
	if (amount < 20)
		return k_army_size_names[k_size_band][article];
	if (amount < 50)
		return k_army_size_names[k_size_dozens][article];
	if (amount < 100)
		return k_army_size_names[k_size_scores][article];
	if (amount < 250)
		return k_army_size_names[k_size_company][article];
	if (amount < 500)
		return k_army_size_names[k_size_hundreds][article];
	if (amount < 1000)
		return k_army_size_names[k_size_host][article];
	if (amount < 2500)
		return k_army_size_names[k_size_legion][article];
	return k_army_size_names[k_size_thousands][article];
};

